package com.lincoln.framework.factories;

import com.lincoln.framework.annotation.Execute;
import com.lincoln.framework.annotation.ExecuteTypeEnum;
import com.lincoln.framework.interfaces.BaseExecute;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @param
 * @author ziyao.peng01@ucarinc.com
 * @description 协议工厂
 * @date 2018/11/29 15:36
 * @return
 */
public class ProtocolFactory {
    private static Logger logger = LoggerFactory.getLogger(ProtocolFactory.class);

    /**
     * 默认设备类型
     */
    private static final int DEFAULT_DEVICE_TYPE = -1;
    /**
     * 默认协议类型
     */
    private static final int DEFAULT_PROTOCOL_TYPE = -1;

    /**
     * 所有扫描到了的协议
     */
    private static Map<String, ProtocolFactoryBean> protocolFactoryBeanMap = new ConcurrentHashMap<>();

    /**
     * 默认的登陆协议
     */
    public static BaseExecute defaultExecute = new DefaultLoginExecute();

    /**
     * 扫描一个新协议(已存在会被覆盖)
     *
     * @param deviceType
     * @param protocolType
     * @param classPath
     * @return
     */
    public static boolean scanProtocol(int deviceType, int protocolType, String classPath) {
        try {
            if (protocolFactoryBeanMap.get(generateKey(deviceType, protocolType)) == null) {
                protocolFactoryBeanMap.put(generateKey(deviceType, protocolType), new ProtocolFactoryBean(deviceType, protocolType, classPath));
            } else {
                protocolFactoryBeanMap.get(generateKey(deviceType, protocolType)).scan(classPath);
            }
        } catch (Exception e) {
            logger.error("扫描协议工厂出错:\n", e);
        }
        return true;
    }

    /**
     * 扫描一个新协议(已存在会被覆盖)
     *
     * @param classPath
     * @return
     */
    public static boolean scanProtocol(String classPath) {
        try {
            Set<Class<?>> set = ProtocolFactoryBean.getClasses(classPath);
            Map<String, Integer> log = new HashMap<>(2);
            for (Class clazz : set) {
                Annotation[] annotations = clazz.getAnnotations();
                if (annotations != null && annotations.length > 0) {
                    for (Annotation annotation : annotations) {
                        if (annotation.annotationType().equals(Execute.class)) {
                            int deviceType1 = ((Execute) annotation).deviceType();
                            int protocolType1 = ((Execute) annotation).protocolType();
                            int[] deviceTypes1 = ((Execute) annotation).deviceTypes();
                            int[] protocolTypes1 = ((Execute) annotation).protocolTypes();
                            ExecuteTypeEnum executeTypeEnum = ((Execute) annotation).executeType();
                            ProtocolFactoryBean protocolFactoryBean = getProtocol(deviceType1, protocolType1);
                            if (protocolFactoryBean == null) {
                                protocolFactoryBean = new ProtocolFactoryBean(deviceType1, protocolType1);
                            }
                            Object object = clazz.newInstance();
                            protocolFactoryBean.addCmd(executeTypeEnum, (BaseExecute) object);
                            setProtocol(deviceType1, protocolType1, protocolFactoryBean);
                            if (log.get("设备类型:" + deviceType1 + "|协议类型:" + protocolType1) == null) {
                                log.put("设备类型:" + deviceType1 + "|协议类型:" + protocolType1, 1);
                            } else {
                                log.put("设备类型:" + deviceType1 + "|协议类型:" + protocolType1, log.get("设备类型:" + deviceType1 + "|协议类型:" + protocolType1) + 1);
                            }
                            for (int deviceType : deviceTypes1) {
                                for (int protocolType : protocolTypes1) {
                                    protocolFactoryBean = getProtocol(deviceType, protocolType);
                                    if (protocolFactoryBean == null) {
                                        protocolFactoryBean = new ProtocolFactoryBean(deviceType, protocolType);
                                    }
                                    object = clazz.newInstance();
                                    protocolFactoryBean.addCmd(executeTypeEnum, (BaseExecute) object);
                                    setProtocol(deviceType, protocolType, protocolFactoryBean);
                                    if (log.get("设备类型:" + deviceType + "|协议类型:" + protocolType) == null) {
                                        log.put("设备类型:" + deviceType + "|协议类型:" + protocolType, 1);
                                    } else {
                                        log.put("设备类型:" + deviceType + "|协议类型:" + protocolType, log.get("设备类型:" + deviceType + "|协议类型:" + protocolType) + 1);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            for (String key : log.keySet()) {
                logger.info(key + "共加载" + log.get(key) + "个解析包");
            }
            return true;
        } catch (Exception e) {
            logger.error("", e);
            return false;
        }
    }

    /**
     * 通过deviceType和protocolType查询对应的工厂类
     *
     * @param deviceType
     * @param protocolType
     * @return
     */
    public static ProtocolFactoryBean getProtocol(Integer deviceType, Integer protocolType) {
        if (deviceType == null || protocolType == null) {
            deviceType = DEFAULT_DEVICE_TYPE;
            protocolType = DEFAULT_PROTOCOL_TYPE;
        }
        return protocolFactoryBeanMap.get(generateKey(deviceType, protocolType));
    }

    /**
     * 通过deviceType和protocolType设置对应的工厂类
     *
     * @param deviceType
     * @param protocolType
     * @return
     */
    public static void setProtocol(int deviceType, int protocolType, ProtocolFactoryBean protocolFactoryBean) {
        protocolFactoryBeanMap.put(generateKey(deviceType, protocolType), protocolFactoryBean);
    }

    /**
     * 生成map的key
     *
     * @param deviceType
     * @param protocolType
     * @return
     */
    private static String generateKey(int deviceType, int protocolType) {
        return deviceType + " " + protocolType;
    }
}
